﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using TelerikedIn.Data;
using TelerikedIn.Models;
using TelerikedIn.WebApp.ViewModels.Account;
using Microsoft.AspNet.Identity;
using TelerikedIn.WebApp.ViewModels.User;
using TelerikedIn.WebApp.ViewModels.Home;

namespace TelerikedIn.WebApp.Controllers
{
    [Authorize]
    public class ProfileController : Controller
    {
        private UowData data;

        private const int MaxImageSize = 102400 / 2;

        public ProfileController() : this(new UowData())
        {
        }

        public ProfileController(UowData data)
	    {
            this.data = data;
	    }

        public ActionResult Update()
        {
            UpdateProfileVM profileInfo = GetProfileInfo();
            return PartialView(profileInfo);
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        [ValidateInput(false)]
        public ActionResult Update(UpdateProfileVM model, string id)
        {
            //model.Id = id;
            if (model != null && ModelState.IsValid)
            {
                var user = model.ToUser;
                user.UserName = User.Identity.Name;
                user.Image = this.data.Users.All().Where(u => u.Id == id).Select(u => u.Image).First();

                try
                {
                    this.data.Users.Update(user);
                    this.data.SaveChanges();
                    return Content("<span class='text-info'>Updated!</span>");
                }
                catch
                {
                    return Content("<span class='text-error'>Server error occured. The data was not saved. Please try again</span>");
                }
            }

            var errors = ModelState.Values.SelectMany(t => t.Errors.Select(e => e.ErrorMessage));
            return Content(string.Join(", ", errors));
        }

        [HttpPost]
        public ActionResult UploadPhoto(string id)
        {
            var message = "User not specified in request.";
            if (id != null)
            {
                var user = this.data.Users.All().FirstOrDefault(u => u.Id == id);
                message = "User not found in database";
                if (user != null)
	            {
                    var file = Request.Files.Get("image-file-upload");
                    message = "No file in the request";

                    var validFileName = IsValidFile(file);
                    if (validFileName)
                    {
                        var bytes = new byte[file.ContentLength];
                        //TODO - add check of first 8 bytes to make sure it's image
                        file.InputStream.Read(bytes, 0, file.ContentLength);
                        user.Image = bytes;
                        this.data.SaveChanges();

                        return Json(new { Message = "<span class='text-info'>Updated!</span>" });
                    }
                    else
                    {
                        if (file != null)
                        {
                            message = "File must be jpg or png and smaller than " + MaxImageSize / 1024 + " KB";
                        }
                    }
	            }
            }

            return Content("<span class='text-error'>" + message + " </span>");
        }
               
        [HttpGet]
        [AllowAnonymous]
        public ActionResult UserDetails(string id)
        {
            if (id == null)
            {
                return Redirect("~/");
            }
            var user = data.Users.All(new []{ "Skills" })
                .FirstOrDefault(u => u.Id == id);

            var publicUserModel = new List<ApplicationUser>() { user }
                .AsQueryable()
                .Select(FullUserVM.FromUser).First();

            if (User.Identity.IsAuthenticated)
            {
                var currentUserId = User.Identity.GetUserId();

                publicUserModel.UsersAreConnected = UsersAreConnected(currentUserId, id);
               
                GetEndorsments(id, publicUserModel, currentUserId);

                return View("UserDetailsFull", publicUserModel);
            }
            else
            {
                return View("UserDetailsPublic", publicUserModel);
            }
        }
       
        [HttpPut]
        public ActionResult Endorse(int skillId, string userId)
        {
            try
            {
                var currentUserId = User.Identity.GetUserId();

                // take the endorsement on this user by current user for this skill
                // if it already exists don't endorse again
                var endorsmentsOnViewedUser = this.data.Endorsments.All()
                    .FirstOrDefault(e => e.ForUserId == userId && e.ByUserId == currentUserId && e.SkillId == skillId );

                if (endorsmentsOnViewedUser == null)
                {
                    this.data.Endorsments.Add(new Endorsment
                    {
                        ByUser = this.data.Users.All().FirstOrDefault(u => u.Id == currentUserId),
                        ForUser = this.data.Users.All().FirstOrDefault(u => u.Id == userId),
                        Skill = this.data.Skills.All().FirstOrDefault(s => s.Id == skillId),
                    });
                    this.data.SaveChanges();

                    return Content("<span title='Remove endorsment' data-skill-id='" + skillId + "' data-sign='+'>-</span>");
                }
                else
                {
                    this.data.Endorsments.Delete(endorsmentsOnViewedUser);
                    this.data.SaveChanges();
                    return Content("<span title='Endorse user' data-skill-id='" + skillId + "'  data-sign='-'>+</span>");
                }
            }
            catch
            {
                return new HttpStatusCodeResult(500, "Database connection lost");
            }
        }

        public ActionResult GetUserPicture(string id = null)
        {
            if (id ==null)
            {
                 id = User.Identity.GetUserId();
            }
            var user = this.data.Users.All().FirstOrDefault(u => u.Id == id);
            byte[] picture = null;
            if (user != null)
	        {
		         picture = user.Image;
	        }

            var imageAsBase64String = Convert.ToBase64String(picture ?? new byte[1]);

            return PartialView("GetUserPicture", imageAsBase64String);
        }

        public ActionResult GetOwnPicture()
        {
            var ownUserId = User.Identity.GetUserId();
            var user = this.data.Users.All().FirstOrDefault(u => u.Id == ownUserId);
            byte[] pictureBytes = null;
            if (user != null)
            {
                pictureBytes = user.Image;
            }
            else
            {
                pictureBytes = new byte[1];
            }

            return PartialView("GetUserPicture", Convert.ToBase64String(pictureBytes));
        }

        private bool IsValidFile(System.Web.HttpPostedFileBase file)
        {
            bool validFileName = true;

            var validFile = file != null && file.ContentLength <= MaxImageSize;

            if (validFile)
            {
                var fileName = file.FileName.ToLower();
                validFileName = fileName.EndsWith(".png") || fileName.EndsWith(".jpg");
            }

            return validFile && validFileName;
        }

        private UpdateProfileVM GetProfileInfo()
        {
            var userId = User.Identity.GetUserId();
            var user = this.data.Users.All()
                .FirstOrDefault(u => u.Id == userId);

            var updateViewModel = new List<ApplicationUser>() { user }
                .AsQueryable()
                .Select(UpdateProfileVM.FromUser).First();

            return updateViewModel;
        }

        private bool UsersAreConnected(string fromUserId, string toUserId)
        {
            var areConnected = true;

            var connection = this.data.Connections.All().FirstOrDefault(c => c.FromUserId == fromUserId && c.ToUserId == toUserId);

            if (connection == null)
            {
                areConnected = false;
            }

            return areConnected;
        }

        private void GetEndorsments(string id, FullUserVM publicUserModel, string currentUserId)
        {

            var endorsmentsOnViewedUser = this.data.Endorsments.All().Where(e => e.ForUserId == id);

            foreach (var skill in publicUserModel.Skills)
            {
                skill.EndorsmentsCount = endorsmentsOnViewedUser.Where(e => e.SkillId == skill.Id).Count();

                if (endorsmentsOnViewedUser.Any(e => e.SkillId == skill.Id && e.ByUserId == currentUserId))
                {
                    skill.IsEndorsed = true;
                }
            }

            publicUserModel.Skills = publicUserModel.Skills
                .OrderByDescending(s => s.EndorsmentsCount)
                .ToList();
        }


	}
}